﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Vanara.PInvoke;

namespace GPDWin4GameBarPowerBackend.AIO.ServiceMain
{
    public class ForegroundChangedReceiver : IDisposable
    {
        public event EventHandler<ForegroundChangedEventArgs> Changed;

        private bool _disposed = false;

        private Process monitorProcess = null;

        public ForegroundChangedReceiver()
        {
            stopSignal = new CancellationTokenSource();
            new Thread(PipeMoniteringThread).Start();
            new Thread(ProcessMoniteringThread).Start();
        }

        public void RestartMonitorProcess()
        {
            monitorProcess?.Kill();
        }

        private void ProcessMoniteringThread()
        {
            while (true)
            {
                try
                {
                    Console.WriteLine("Starting foreground monitoring process: ");
                    monitorProcess = ProcessAsUser.Start("\"" + Process.GetCurrentProcess().MainModule.FileName + "\" " + ForegroundChangedHelper.Program.type, true);

                    Console.WriteLine("Monitoring Process Started: " + monitorProcess.Id);
                    monitorProcess.WaitForExit();

                    Console.WriteLine("Monitoring Process Exited.");
                    for (int i = 0; i < 10; i++)
                    {
                        Thread.Sleep(800);
                        if (_disposed)
                        {
                            return;
                        }
                    }
                }
                catch (Win32Exception ex)
                {
                    Console.WriteLine("Cannot start monitoring process: "+ex);
                    for (int i = 0; i < 10; i++)
                    {
                        Thread.Sleep(800);
                        if (_disposed)
                        {
                            return;
                        }
                    }
                }
            }
            

        }

        CancellationTokenSource stopSignal;
        private void PipeMoniteringThread()
        {
            PipeSecurity ps = new PipeSecurity();
            ps.AddAccessRule(new PipeAccessRule("Everyone", PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow));
            ps.AddAccessRule(new PipeAccessRule("CREATOR OWNER", PipeAccessRights.FullControl, AccessControlType.Allow));
            ps.AddAccessRule(new PipeAccessRule("SYSTEM", PipeAccessRights.FullControl, AccessControlType.Allow));
            while (true)
            {
                using (NamedPipeServerStream namedPipeServerStream = new NamedPipeServerStream(ForegroundChangedHelper.Program.pipeId, PipeDirection.InOut, 114, PipeTransmissionMode.Byte, PipeOptions.None, 1024, 1024, ps))
                {

                    Console.WriteLine("Pipe Server Started. ");
                    var asyncWaitContext = namedPipeServerStream.WaitForConnectionAsync();
                    asyncWaitContext.Wait(stopSignal.Token);
                    if(stopSignal.IsCancellationRequested)
                    {
                        return;
                    }

                    Console.WriteLine("Pipe Server Connected. ");
                    StreamReader sr = new StreamReader(namedPipeServerStream);
                    string line = null;
                    try
                    {
                        while (true)
                        {

                            var readLineResult = sr.ReadLineAsync();
                            readLineResult.Wait(stopSignal.Token);
                            if (stopSignal.IsCancellationRequested)
                            {
                                return;
                            }
                            line = readLineResult.Result;
                            if (line == null)
                            {
                                break;
                            }
                            var result = JsonConvert.DeserializeObject<CurrentForegroundWindow>(line);
                            Changed?.Invoke(this, new ForegroundChangedEventArgs() { ProcessPath = result.ProcessPath, WindowTitle = result.WindowTitle });
                        }
                    }catch (Exception ex) {
                        Console.WriteLine("Failed to receive signal from MonitorProcess");
                        Console.WriteLine(ex.ToString());
                    }
                    try
                    {
                        namedPipeServerStream.Disconnect();
                    }
                    catch { }
                }
                    
            }
        }


        public void Dispose()
        {
            _disposed = true;
            stopSignal.Cancel();
            try
            {
                monitorProcess?.Kill();
            }
            catch { }
        }
    }

    public class CurrentForegroundWindow
    {
        public string ProcessPath { get; set; }
        public string WindowTitle { get; set; }
    }

    public class ForegroundChangedEventArgs : EventArgs
    {
        public ForegroundChangedEventArgs() { }

        public string ProcessPath { get; set; }
        
        public string WindowTitle { get; set; }
    
    }
}
